#pragma once
#ifndef HOOK_H
#define HOOK_H

#ifndef NOSTDAFX
#include "StdAfx.h"
#endif

#include <set>
//#include <map>
#include <boost/unordered_map.hpp>

class Hook;
struct DynamicData;
typedef boost::unordered_map<const char*, DynamicData> VlareHashMap;
typedef boost::unordered_map<const char*, DynamicData> ElementMemberMap;
typedef Hook VlarePair;

#include "DynamicData.h"
#include "Element.h"

typedef void (*Listener)(const Element *const pElem, const char *const szName, const DynamicData& oldValue, const DynamicData& newValue);

/// Hooks are containers for DynamicData, they watch access to them
/** 
 *	As far as possible, the existence of Hooks is hiden towards the user!
 *	When DynamicData is set or retrieved, Hooks can fire the corresponding events.
 *	While DynamicData is exchanged during runtime a lot of times (maybe once a frame), Hooks are consistent.
 *	An Listener that has registered once, will be invoked on events until it is Unregistered.
 *	This is impossible for something resting inside DynamicData (VlareFunction)
 *	There are "set"-Listeners, which are invoked when a property is set
 *	There are "get"-Listeners, which are invoked when a property is retrieved
 *	BEWARE: You can't rely on the correct invokation moment of the "set"-notification.
 *			e.g.: the "x"-Position member is only updated on request, when the position of an
 *			element changed by setting its vector.
 *			Why so complicated? -> This reduces subsequent built matrices and vectors!
 *			(setting an x value and y value next, this would result in 2 vector and 2 matrix updates otherwise)
 */
typedef std::pair<const char *const, DynamicData> _HookBase;
class Hook : public _HookBase
{
	// first: const char *const	szName;
	const Element *const	pElem;

	/// Up2Date Algorithm:
	/** When the Hook is set, all Hooks in 'invalidateOnUpdate'
	 *	are marked as not-up2date. This is done via pUp2Date:
	 *  pUp2Date points to the Hook which invalidated this member last.
	 *	The next time this invalidated Hook is called 'constructUp2Date'
	 *  is called with the second parameter being the pUp2Date-Hook
	 **/
	const Hook*				pUp2Date;
	void					(*constructUp2Date)(Hook& me, const Hook *const up2d);
	std::set<Hook>			invalidateOnUpdate;
	// second: DynamicData			data;
	std::set<Listener>	listener;
	std::set<Listener>	setListener;
public:
	void				Set(const DynamicData& );
	const DynamicData	Get() const;
	void				AddGetListener(Listener );
	void				AddSetListener(Listener );
	void				RemoveGetListener(Listener );
	void				RemoveSetListener(Listener );

	///Operators manipulate get- AND(!) set-listener
	Hook& operator= (const DynamicData& );
	Hook& operator+= (const Listener& );
	Hook& operator-= (const Listener& );
	operator const DynamicData () const;

	//The Compiler is not clever enough to implicit
	//convert "Hook->DynamicData->Atom" so we have
	//to give her a hint...
	operator const char* () const;
	operator int () const;
	operator Vloat () const;
	operator void* () const;
	//operator DynamicData* () const;
	operator VlareFunction () const;

	//TODO: GetName() GetElement();

	Hook(const char *const szName, const DynamicData& val, const Element *const pElem=0x0);
	~Hook(void);
};

#endif